package com.yjw.rpc.server;


import com.sun.org.apache.regexp.internal.RE;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class RpcServer {

    private static final ExecutorService EXECUTOR_SERVICE = Executors.newCachedThreadPool();

    /**
     * 发布服务
     *
     * @param service 服务对象，用来执行方法返回结果给客户端
     * @param port    ServerSocket 端口号
     */
    public void publisher(Object service, int port) {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(port);
            // 循环监听
            while (true) {
                Socket socket = serverSocket.accept();
                EXECUTOR_SERVICE.execute(new ProcessHandler(socket, service));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 处理Socket请求
     */
    class ProcessHandler implements Runnable {

        private Object service;
        private Socket socket;

        public ProcessHandler(Socket socket, Object service) {
            this.socket = socket;
            this.service = service;
        }

        /**
         * 接收客户端请求，反射执行service方法，输出结果数据给客户端
         */
        public void run() {
            ObjectInputStream objectInputStream = null;
            ObjectOutputStream objectOutputStream = null;
            try {
                // 接收客户端请求
                objectInputStream = new ObjectInputStream(socket.getInputStream());
                RpcRequest rpcRequest = (RpcRequest) objectInputStream.readObject();

                // 反射执行service方法
                Object result = invoke(rpcRequest);

                // 输出结果数据给客户端
                objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
                objectOutputStream.writeObject(result);
                objectOutputStream.flush();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (objectInputStream != null) {
                    try {
                        objectInputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (objectOutputStream != null) {
                    try {
                        objectOutputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        /**
         * 反射执行service方法，返回结果
         *
         * @param rpcRequest 传输对象
         * @return
         */
        private Object invoke(RpcRequest rpcRequest) throws NoSuchMethodException,
                InvocationTargetException, IllegalAccessException {
            Object[] parameters = rpcRequest.getParameters();
            int length = parameters.length;
            Class<?>[] parameterTypes = new Class[length];
            for (int i = 0; i < length; i++) {
                parameterTypes[i] = parameters[i].getClass();
            }
            String methodName = rpcRequest.getMethodName();
            Method method = service.getClass().getMethod(methodName, parameterTypes);
            Object result = method.invoke(service, parameters);
            return result;
        }
    }
}
